/// <reference path="../index.d.ts" />

/**
 * 传入dialog element，使dialog可拖动
 * @param el
 * @returns
* 让 el-dialog 可拖拽（修复左偏/1/3 偏移）
* 用法：在对话框打开后，传入包裹元素（通常是弹层挂载节点或 body）
*/

export const applyDialogDraggable = (el: HTMLElement) => {
  const dialog = el.querySelector('.el-dialog__wrapper > .el-dialog') as HTMLElement | null
  const header = el.querySelector('.el-dialog__header') as HTMLElement | null
  if (!dialog || !header) return

  // 统一坐标系：fixed + 去 margin/transform（Element 默认可能有 translate(-50%,-50%)）
  dialog.style.position = 'fixed'
  dialog.style.margin = '0'
  dialog.style.transform = 'none'

  // 初始居中（只在没设过 left/top 的时候）
  const ensureCentered = () => {
    const rect = dialog.getBoundingClientRect()
    if (!dialog.style.left) dialog.style.left = `${Math.max(0, (window.innerWidth - rect.width) / 2)}px`
    if (!dialog.style.top) dialog.style.top = `${Math.max(0, (window.innerHeight - rect.height) / 2)}px`
  }
  // 等一帧，确保尺寸稳定（避免过渡动画中尺寸不准）
  requestAnimationFrame(ensureCentered)

  header.style.cursor = 'move'
  header.style.userSelect = 'none'

  let startX = 0
  let startY = 0
  let startLeft = 0
  let startTop = 0

  const onMove = (e: MouseEvent | TouchEvent) => {
    const p = 'touches' in e ? e.touches[0] : (e as MouseEvent)
    const dx = p.clientX - startX
    const dy = p.clientY - startY

    const w = dialog.offsetWidth
    const h = dialog.offsetHeight
    const vw = window.innerWidth
    const vh = window.innerHeight

    let newLeft = startLeft + dx
    let newTop = startTop + dy

    // 约束在可视区域
    if (newLeft < 0) newLeft = 0
    if (newTop < 0) newTop = 0
    if (newLeft + w > vw) newLeft = vw - w
    if (newTop + h > vh) newTop = vh - h

    dialog.style.left = `${newLeft}px`
    dialog.style.top = `${newTop}px`
  }

  const stop = () => {
    document.removeEventListener('mousemove', onMove as any)
    document.removeEventListener('mouseup', stop)
    document.removeEventListener('touchmove', onMove as any, { passive: false } as any)
    document.removeEventListener('touchend', stop)
  }

  const start = (e: MouseEvent | TouchEvent) => {
    // 避免拖到关闭按钮
    const target = (e.target as HTMLElement)
    if (target.closest('.el-dialog__headerbtn')) return

    e.preventDefault()

    const p = 'touches' in e ? e.touches[0] : (e as MouseEvent)
    const rect = dialog.getBoundingClientRect()

    // 在按下瞬间，用视口坐标作为起点（统一坐标系）
    startX = p.clientX
    startY = p.clientY
    startLeft = rect.left
    startTop = rect.top

    document.addEventListener('mousemove', onMove as any)
    document.addEventListener('mouseup', stop)
    document.addEventListener('touchmove', onMove as any, { passive: false } as any)
    document.addEventListener('touchend', stop)
  }

  header.addEventListener('mousedown', start)
  header.addEventListener('touchstart', start, { passive: false })

  // 窗口尺寸变化时，保证不出屏
  const onResize = () => {
    const w = dialog.offsetWidth
    const h = dialog.offsetHeight
    const vw = window.innerWidth
    const vh = window.innerHeight
    const rect = dialog.getBoundingClientRect()
    let left = rect.left
    let top = rect.top
    if (left + w > vw) left = Math.max(0, vw - w)
    if (top + h > vh) top = Math.max(0, vh - h)
    dialog.style.left = `${left}px`
    dialog.style.top = `${top}px`
  }
  window.addEventListener('resize', onResize)

  // 可选：返回销毁函数（对话框关闭时调用）
  return () => {
    header.removeEventListener('mousedown', start)
    header.removeEventListener('touchstart', start as any)
    window.removeEventListener('resize', onResize)
    stop()
    header.style.cursor = ''
    header.style.userSelect = ''
  }
}

export default {
  data: () => ({
    closeOnClickModal: true,
    closeOnPressEscape: true,
    destroyOnClose: true,
    modalAppendToBody: false,
    modal: true,
    appendToBody: false,
    customClass: '',
    width: '70%',
    top: '15vh',
    fullscreen: false,
    showClose: true,
    beforeClose: undefined,
    onClose: undefined,
    onClosed: undefined,
    onOpened: undefined,
    onOpen: undefined,
    onDestroy: undefined,
    component: null,
    loading: false,
    loadingButton: '',
    disabledButton: '',
    buttons: [],
    directives: [],
    scopedSlots: null,
    props: {},
    on: {},
    title: null,
    visible: false,
    tag: 'el-dialog'
  }),
  methods: {
    close() {
      this.component = null
      this.visible = false
      setTimeout(() => {
        this.onClose?.()
        this.destroy()
      }, 500)
    },
    onButtonClicked(button: ButtonProps) {
      const { callback, disabled, loading, cid, emit } = button
      if (disabled || loading) return
      if (emit) return this.$emit(emit)
      if (!callback) return

      if (typeof callback === 'function') return callback({ component: this.$refs.component, dialog: this })

      if (typeof callback === 'string') {
        if (cid) return this[callback]()
        this.$refs.component?.[callback]?.({
          component: this.$refs.component,
          dialog: this
        })
      }
    }
  },
  render(h: any) {
    const { visible, props, loading, width, showClose, loadingButton, disabledButton, component, buttons, on, title } =
      this
    return h(
      this.tag,
      {
        props: this,
        directives: this.directives,
        scopedSlots: Object.keys(this.scopedSlots || {}).reduce((acc, key) => ({
          ...acc,
          [key]: () => this.scopedSlots?.[key]({ h, context: this })
        }), {} as any),
        on: {
          open: () => this.onOpen?.(),
          opened: () => this.onOpened?.(),
          closed: (e: any) => (this.onClosed?.(e), this.onDestroy?.()),
          close: this.close
        }
      },
      [
        h(component, {
          ref: 'component',
          props: {
            loading,
            visible,
            buttons,
            title,
            showClose,
            width: window.innerWidth < 400 ? '90%' : width,
            loadingButton,
            disabledButton,
            ...props
          },
          on: {
            ...on,
            'update:title': (v: string) => (this.title = v),
            'update:width': (v: string | number) => (this.width = v),
            'update:visible': (v: boolean) => (this.visible = v),
            'update:showClose': (v: boolean) => (this.showClose = v),
            'update:loading': (v: boolean) => (this.loading = v),
            'update:buttons': (v: ButtonProps[]) => (this.buttons = v),
            'update:fullscreen': (v: boolean) => (this.fullscreen = v),
            'update:loadingButton': (v: string[]) => (this.loadingButton = v),
            'update:disabledButton': (v: string[]) => (this.disabledButton = v)
          }
        }),
        ...buttons.map((button: ButtonProps) => {
          const { text, loading, disabled, name, type = 'primary' } = button
          return h(
            'el-button',
            {
              slot: 'footer',
              on: { click: () => this.onButtonClicked(button) },
              props: {
                type,
                loading: loadingButton.includes(name) || loading,
                disabled: disabledButton.includes(name) || disabled
              }
            },
            text
          )
        })
      ]
    )
  }
}
